package com.sg.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.PropDesc;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.sg.common.ConvertValue;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @Author minguk
 * @Description 类型转换: Entity - Vo转换
 * @Date 2022/8/11 15:37
 * @Param [params]
 **/
@Slf4j
public class ConvertUtil {
    public static final Logger logger = LoggerFactory.getLogger(ConvertUtil.class);

    private ConvertUtil() {
    }

    public static <T> T entityToVo(Object source, Class<T> target) {
        if (source == null) {
            return null;
        }
        T targetObject = null;
        try {
            targetObject = target.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(source, targetObject);
        } catch (Exception e) {
            log.error("error", e);
        }
        return targetObject;
    }

    public static <T> List<T> entityToVoList(Collection<?> sourceList, Class<T> target) {
        if (sourceList == null) {
            return Collections.emptyList();
        }
        List<T> targetList = new ArrayList<>(sourceList.size());
        try {
            for (Object source : sourceList) {
                T targetObject = target.getDeclaredConstructor().newInstance();
                BeanUtils.copyProperties(source, targetObject);
                targetList.add(targetObject);
            }
        } catch (Exception e) {
            logger.error("convert error ", e);
        }
        return targetList;
    }

    /**
     * 获取对象中为null的参数
     *
     * @param source
     * @return
     */
    public static String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<>();
        for (java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) emptyNames.add(pd.getName());
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    /**
     * 类型转换: Entity - Vo转换
     * 可将Entity中的字典字段转为枚举
     *
     * @param source 源对象
     * @param target 目标类
     * @return T
     * @author 狮子
     * @date 2022-12-01
     */
    public static <T> T entityToVoEnum(Object source, Class<T> target) {
        if (source == null) {
            return null;
        }
        T targetObject = null;
        try {
            targetObject = target.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        BeanUtils.copyProperties(source, Objects.requireNonNull(targetObject));
        T finalTargetObject = targetObject;
        BeanUtil.descForEach(target, propDesc -> {
            // 遍历所有字段
            if (propDesc.getFieldClass().isEnum()) {
                // 如果是枚举
                // 获取源字段值
                Object sourceProperty = BeanUtil.getProperty(source, propDesc.getFieldName());
                convert(finalTargetObject, propDesc, sourceProperty);
            }
        });
        return targetObject;
    }

    public static <T> void convert(T finalTargetObject, PropDesc propDesc, Object sourceProperty) {
        if (sourceProperty != null) {
            try {
                // 反射获取该字段的类型
                Class<?> aClass = Class.forName(propDesc.getFieldType().getTypeName());
                for (Method method : aClass.getDeclaredMethods()) {
                    // 获取注解
                    JsonCreator annotation = method.getAnnotation(JsonCreator.class);
                    if (null != annotation && JsonCreator.Mode.DELEGATING.equals(annotation.mode())) {
                        // 调用该静态方法获取枚举值
                        Object invoke = method.invoke(null, sourceProperty);
                        propDesc.setValue(finalTargetObject, invoke);
                        break;
                    }
                }
            } catch (IllegalAccessException | InvocationTargetException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 类型转换: Entity - Vo List转换
     * 可将Entity中的字典字段转为枚举
     *
     * @param sourceList 源列表
     * @param target     目标类
     * @return T
     * @author 狮子
     * @date 2022-12-01
     */
    public static <T> List<T> entityToVoListEnum(Collection<?> sourceList, Class<T> target) {
        if (sourceList == null) {
            return Collections.emptyList();
        }
        List<T> targetList = new ArrayList<>(sourceList.size());
        try {
            for (Object source : sourceList) {
                targetList.add(entityToVoEnum(source, target));
            }
        } catch (Exception e) {
            logger.error("convert error ", e);
        }
        return targetList;
    }

    /**
     * 类型转换: Entity - Vo转换
     * 可将Entity中的字典字段转为枚举
     * 枚举转换字段需加ConvertValue注解
     *
     * @param source 源对象
     * @param target 目标类
     * @return T
     * @author 狮子
     * @date 2022-12-01
     */
    public static <T> T entityToVoSimple(Object source, Class<T> target) {
        if (source == null) {
            return null;
        }
        T targetObject = null;
        try {
            targetObject = target.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        BeanUtils.copyProperties(source, Objects.requireNonNull(targetObject));
        T finalTargetObject = targetObject;
        BeanUtil.descForEach(target, propDesc -> {
            // 遍历所有字段
            if (propDesc.getFieldClass().isEnum()) {
                // 如果是枚举
                // 获取源字段值
                Object sourceProperty = BeanUtil.getProperty(source, propDesc.getFieldName());
                if (sourceProperty != null) {
                    try {
                        // 获取该字段的类
                        Class<?> aClass = Class.forName(propDesc.getFieldType().getTypeName());
                        Field field = null;
                        field = getField(aClass, field);
                        if (field != null) {
                            getValue(finalTargetObject, propDesc, sourceProperty, aClass, field);
                        }
                    } catch (IllegalAccessException | InvocationTargetException | ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        return targetObject;
    }

    /**
     * 类型转换: Entity - Vo List转换
     * 可将Entity中的字典字段转为枚举
     *
     * @param sourceList 源列表
     * @param target     目标类
     * @return T
     * @author 狮子
     * @date 2022-12-01
     */
    public static <T> List<T> entityToVoListSimple(Collection<?> sourceList, Class<T> target) {
        if (sourceList == null) {
            return Collections.emptyList();
        }
        List<T> targetList = new ArrayList<>(sourceList.size());
        try {
            for (Object source : sourceList) {
                targetList.add(entityToVoSimple(source, target));
            }
        } catch (Exception e) {
            logger.error("convert error ", e);
        }
        return targetList;
    }

    public static <T> void getValue(T finalTargetObject, PropDesc propDesc, Object sourceProperty, Class<?> aClass, Field field) throws IllegalAccessException, InvocationTargetException {
        for (Method method : aClass.getDeclaredMethods()) {
            if ("values".equals(method.getName())) {
                Object invoke = method.invoke(null);
                int length = Array.getLength(invoke);
                for (int i = 0; i < length; i++) {
                    Object o = Array.get(invoke, i);
                    if (sourceProperty.equals(BeanUtil.getFieldValue(o, field.getName()))) {
                        propDesc.setValue(finalTargetObject, o);
                        break;
                    }
                }
                break;
            }
        }
    }

    public static Field getField(Class<?> aClass, Field field) {
        for (Field field1 : aClass.getDeclaredFields()) {
            ConvertValue annotation = field1.getAnnotation(ConvertValue.class);
            if (null != annotation) {
                field = field1;
                break;
            }
        }
        return field;
    }

    public static <T> List<T> objctToList(Object obj, Class<T> clazz) {
        List<T> res = new ArrayList<>();
        if (obj instanceof List<?>) {
            for (Object o : ((List<?>) obj)) {
                res.add(clazz.cast(o));
            }
            return res;
        }
        return null;
    }

    /**
     * 中文验证
     *
     * @param strName
     * @return
     */
    public static boolean isChinese(String strName) {
        char[] ch = strName.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            char c = ch[i];
            if (isChinese(c)) {
                return true;
            }
        }
        return false;
    }

    public static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
            return true;
        }
        return false;
    }


    public static boolean isAllFieldNull(Object obj) throws IllegalAccessException {
        Class<?> aClass = obj.getClass();
        Field[] fs = aClass.getDeclaredFields();
        boolean flag = true;
        for (Field f : fs) {
            f.setAccessible(true);
            Object o = f.get(obj);
            if (o != null) {
                flag = false;
            }
        }
        return flag;
    }


}

